
#include <cstdio>
#include <BApplication>
#include <BScript>
#include "member_BScript.h"
#include "member_BSource.h"
#include "member_BClass.h"
#include "member_BObject.h"

using namespace BWE;

#define member					(*(member_BScript*)_ptr)
#define member_allocate()		_ptr = new member_BScript(this)
#define member_release()		delete (member_BScript*)_ptr

BScript::BScript()
{
	member_allocate();
}
BScript::BScript(const BString& name) : BObject(name)
{
	member_allocate();
}
BScript::~BScript()
{
	member_release();
}

void BScript::copy(const BScript* other)
{
	object_member(this)->name = object_member(other)->name;

	member.path = script_member(other)->path;
	member.breakpointSet = script_member(other)->breakpointSet;
	member.includePaths = script_member(other)->includePaths;
	member.importPaths = script_member(other)->importPaths;
	member.cachedFileMap = script_member(other)->cachedFileMap;

	member.presetVariants = script_member(other)->presetVariants;

	for (int i = 0; i < script_member(other)->sources.size(); i++)
	{
		BSource* source = script_member(other)->sources[i];
		source = source->clone();
		this->insertSource(source);
	}

	member.presetEnumMap = script_member(other)->presetEnumMap;
	for (auto it = member.presetEnumMap.begin(); it.valid(); ++it)
	{
		BEnum* enm = *it;
		*it = enm->clone();
	}

	member.presetClassMap = script_member(other)->presetClassMap;
	for (auto it = member.presetClassMap.begin(); it.valid(); ++it)
	{
		BClass* cls = *it;
		*it = cls->clone();
	}

	member.presetFunctionMap = script_member(other)->presetFunctionMap;
	for (auto it = member.presetFunctionMap.begin(); it.valid(); ++it)
	{
		FuncInfo* finfo = *it;
		FuncInfo* fi = new FuncInfo();
		fi->line = finfo->line;
		fi->type = finfo->type;
		fi->cfunc = finfo->cfunc;
		fi->sfunc = finfo->sfunc;
		fi->params = finfo->params;
		*it = fi;
	}

	member.sequence = script_member(other)->sequence;
	for (int i = 0; i < member.sequence.size(); i++)
	{
		BExpHolder& exp = member.sequence[i];
		member.sequence[i] = member.cloneExp(exp);
	}

}
BScript* BScript::clone() const
{
	BScript* script = new BScript();
	script->copy(this);
	return script;
}

void BScript::setPath(const BString& path)
{
	if (member.path != path)
	{
		member.path = path;
		if (this->checks(Signal_PathChanged))
			this->emit(Signal_PathChanged, path);
	}
}
const BString& BScript::path() const
{
	return member.path;
}

bool BScript::insertSource(BSource* source)
{
	if (!source)
		return false;
	if (source_member(source)->script == this)
		return true;
	member.sources.append(source);
	if (BScript* script = source_member(source)->script)
		script->removeSource(source);
	source_member(source)->script = this;
	if (this->checks(Signal_Insert))
		this->emit(Signal_Insert, BValue(source, this));
	return true;
}
bool BScript::removeSource(BSource* source)
{
	if (!source)
		return false;
	if (source_member(source)->script == this)
	{
		BHolder<BSource> holder(source);
		source_member(source)->script = 0;
		member.sources.remove(source);
		if (this->checks(Signal_Remove))
			this->emit(Signal_Remove, BValue(source, this));
		return true;
	}
	return false;
}
bool BScript::containSource(const BSource* source)
{
	return member.sources.contain(source);
}
bool BScript::clearSources()
{
	while (BSource* source = member.sources.last())
	{
		removeSource(source);
	}
	this->emit(Signal_Clear);
	return true;
}

int BScript::sourceCount() const
{
	return member.sources.size();
}
BSource* BScript::source(int index)
{
	return member.sources(index);
}
const BSource* BScript::source(int index) const
{
	return member.sources(index);
}
BSource* BScript::source(const BString& name)
{
	if (name.empty())
		return 0;
	for (int i = 0; i < member.sources.size(); i++)
	{
		BSource* source = member.sources[i];
		if (source->name() == name)
			return source;
	}
	return 0;
}
const BSource* BScript::source(const BString& name) const
{
	if (name.empty())
		return 0;
	for (int i = 0; i < member.sources.size(); i++)
	{
		const BSource* source = member.sources[i];
		if (source->name() == name)
			return source;
	}
	return 0;
}

bool BScript::insertIncludePath(const BString& includePath)
{
	if (member.includePaths.insert(includePath))
	{
		this->emit(Signal_Changed);
		return true;
	}
	return false;
}
bool BScript::removeIncludePath(const BString& includePath)
{
	if (member.includePaths.remove(includePath))
	{
		this->emit(Signal_Changed);
		return true;
	}
	return false;
}
bool BScript::containIncludePath(const BString& includePath)
{
	return member.includePaths.contain(includePath);
}
bool BScript::clearIncludePaths()
{
	if (member.includePaths.size())
	{
		member.includePaths.clear();
		this->emit(Signal_Changed);
		return true;
	}
	return false;
}

int BScript::includePathCount() const
{
	return member.includePaths.size();
}
const BString& BScript::includePath(int index) const
{
	return member.includePaths(index);
}

bool BScript::insertImportPath(const BString& includePath)
{
	if (member.importPaths.insert(includePath))
	{
		this->emit(Signal_Changed);
		return true;
	}
	return false;
}
bool BScript::removeImportPath(const BString& includePath)
{
	if (member.importPaths.remove(includePath))
	{
		this->emit(Signal_Changed);
		return true;
	}
	return false;
}
bool BScript::containImportPath(const BString& includePath)
{
	return member.importPaths.contain(includePath);
}
bool BScript::clearImportPaths()
{
	if (member.importPaths.size())
	{
		member.importPaths.clear();
		this->emit(Signal_Changed);
		return true;
	}
	return false;
}

int BScript::importPathCount() const
{
	return member.importPaths.size();
}
const BString& BScript::importPath(int index) const
{
	return member.importPaths(index);
}

bool BScript::registEnum(BEnum* enm)
{
	if (enm == 0)
		return false;
	if (member.presetEnumMap.contain(enm->name()))
		return true;
	member.presetEnumMap.insert(enm->name(), enm);
	return true;
}
bool BScript::unregistEnum(BEnum* enm)
{
	if (enm == 0)
		return false;
	member.presetEnumMap.remove(enm->name());
	return true;
}
bool BScript::unregistEnum(const BString& type)
{
	if (type.empty())
		return false;
	member.presetEnumMap.remove(type);
	return false;
}

int BScript::registedEnumCount() const
{
	return member.presetEnumMap.size();
}
BEnum* BScript::registedEnum(int index)
{
	auto it = member.presetEnumMap.seek(index);
	if (it.valid())
		return it.value();
	return 0;
}
const BEnum* BScript::registedEnum(int index) const
{
	auto it = member.presetEnumMap.seek(index);
	if (it.valid())
		return it.value();
	return 0;
}
BEnum* BScript::registedEnum(const BString& type)
{
	return member.presetEnumMap(type);
}
const BEnum* BScript::registedEnum(const BString& type) const
{
	return member.presetEnumMap(type);
}

bool BScript::registClass(BClass* cls)
{
	if (!cls)
		return false;
	if (member.presetClassMap.contain(cls->name()))
	{
		member.errorMessage() << "Regist class failed : " << cls->name() << " is already existing.";
		if (this->checks(Signal_Error))
			this->emit(Signal_Error, member.message);
		return false;
	}
	for (int i = 0; i < class_member(cls)->inherits.size(); i++)
	{
		BExp* exp = class_member(cls)->inherits.at(i);
		exp->value = member.presetClassMap(exp->type);
		if (exp->value.empty())
		{
			member.errorMessage() << "Regist class failed : " << cls->name() << " inherits from invalid class : " << exp->type << ".";
			if (this->checks(Signal_Error))
				this->emit(Signal_Error, member.message);
		}
	}
	member.presetClassMap.insert(cls->name(), cls);
	return true;
}
bool BScript::unregistClass(BClass* cls)
{
	if (!cls)
		return false;
	if (member.presetClassMap.remove(cls->name()))
	{
		return true;
	}
	return false;
}
bool BScript::unregistClass(const BString& type)
{
	if (type.empty())
		return false;
	auto it = member.presetClassMap.find(type);
	if (it.valid())
	{
		member.presetClassMap.erase(it);
		return true;
	}
	return false;
}

int BScript::registedClassCount() const
{
	return member.presetClassMap.size();
}
BClass* BScript::registedClass(int index)
{
	return member.presetClassMap.seek(index).value();
}
const BClass* BScript::registedClass(int index) const
{
	return member.presetClassMap.seek(index).value();
}
BClass* BScript::registedClass(const BString& type)
{
	return member.presetClassMap(type);
}
const BClass* BScript::registedClass(const BString& type) const
{
	return member.presetClassMap(type);
}

bool BScript::registFunction(const BString& declare, Function function)
{
	if (declare.empty())
	{
		member.errorMessage() << "Analyse function failed : empty declare !";
		this->emit(Signal_Error, member.message);
		return false;
	}

	if(function == 0)
	{
		member.errorMessage() << "Analyse function failed : empty function !";
		this->emit(Signal_Error, member.message);
		return false;
	}

	BString name = declare;
	name.trimmed();
	if (name.removeTail(';'))
	{
		name.trimmed();
	}

	FuncInfoHolder finfo = new FuncInfo();
	if (!AnalyseDeclare(name, finfo->type, finfo->params))
	{
		member.errorMessage() << "Analyse function failed : " << declare << " !";
		this->emit(Signal_Error, member.message);
		return false;
	}
	finfo->cfunc = function;
	if (member.presetFunctionMap.contain(name))
	{
		member.errorMessage() << "Multiple regist function : " << name << " !";
		this->emit(Signal_Error, member.message);
	}
	member.presetFunctionMap[name] = finfo;
	return true;
}
bool BScript::unregistFunction(Function function)
{
	for (auto it = member.presetFunctionMap.begin(); it.valid(); ++it)
	{
		FuncInfo* finfo = it.value();
		if (finfo->cfunc == function)
		{
			member.presetFunctionMap.erase(it);
			return true;
		}
	}
	return false;
}
bool BScript::unregistFunction(const BString& name)
{
	return member.presetFunctionMap.remove(name);
}

int BScript::registedFunctionCount() const
{
	return member.presetFunctionMap.size();
}
Function BScript::registedFunction(int index) const
{
	auto it = member.presetFunctionMap.seek(index);
	if (FuncInfo* finfo = it.value())
		return finfo->cfunc;
	return 0;
}
Function BScript::registedFunction(int index, BString& name) const
{
	auto it = member.presetFunctionMap.seek(index);
	if (FuncInfo* finfo = it.value())
	{
		name = it.key();
		return finfo->cfunc;
	}
	return 0;
}
Function BScript::registedFunction(int index, BString& type, BString& name) const
{
	auto it = member.presetFunctionMap.seek(index);
	if (FuncInfo* finfo = it.value())
	{
		type = finfo->type;
		name = it.key();
		return finfo->cfunc;
	}
	return 0;
}

const BValue& BScript::createVariant(const char* type, const char* name, const BValue& value)
{
	if (!type && !name)
		return member.presetVariants.def().value;
	for (int i = 0; i < member.presetVariants.size(); i++)
	{
		const VariantInfo& vinfo = member.presetVariants[i];
		if (vinfo.name == name)
			return member.presetVariants.def().value;
	}
	VariantInfo& vinfo = member.presetVariants.append();
	vinfo.type = type;
	if (vinfo.type.beginWith("const "))
	{
		vinfo.cnst = true;
		vinfo.type.remove("const ");
	}
	vinfo.name = name;
	this->create(vinfo.type, vinfo.value, value);
	return vinfo.value;
}
const BValue& BScript::createVariant(const BString& type, const BString& name, const BValue& value)
{
	if (type.empty() || name.empty())
		return member.presetVariants.def().value;
	for (int i = 0; i < member.presetVariants.size(); i++)
	{
		const VariantInfo& var = member.presetVariants[i];
		if (var.name == name)
			return member.presetVariants.def().value;
	}
	VariantInfo& vinfo = member.presetVariants.append();
	vinfo.type = type;
	if (vinfo.type.beginWith("const "))
	{
		vinfo.cnst = true;
		vinfo.type.remove("const ");
	}
	vinfo.name = name;
	this->create(type, vinfo.value, value);
	return vinfo.value;
}
bool BScript::removeVariant(const char* name)
{
	for (int i = 0; i < member.presetVariants.size(); i++)
	{
		const VariantInfo& vinfo = member.presetVariants[i];
		if (vinfo.name == name)
		{
			if (BClass* cls = vinfo.value)
			{
				class_member(cls)->script = this;
			}
			member.presetVariants.remove(i);
			return false;
		}
	}
	return false;
}
bool BScript::removeVariant(const BString& name)
{
	for (int i = 0; i < member.presetVariants.size(); i++)
	{
		const VariantInfo& vinfo = member.presetVariants[i];
		if (vinfo.name == name)
		{
			if (BClass* cls = vinfo.value)
			{
				class_member(cls)->script = this;
			}
			member.presetVariants.remove(i);
			return false;
		}
	}
	return false;
}

int BScript::variantCount() const
{
	return member.presetVariants.size();
}
BValue& BScript::variant(int index)
{
	return member.presetVariants(index).value;
}
BValue& BScript::variant(int index, BString& type, BString& name)
{
	VariantInfo& vinfo = member.presetVariants(index);
	type = vinfo.type;
	name = vinfo.name;
	return vinfo.value;
}
const BValue& BScript::variant(int index) const
{
	return member.presetVariants(index).value;
}
const BValue& BScript::variant(int index, BString& type, BString& name) const
{
	VariantInfo& vinfo = member.presetVariants(index);
	type = vinfo.type;
	name = vinfo.name;
	return vinfo.value;
}

void BScript::setDebugging(bool debugging)
{
	AutoLock lock(this);
	if (member.debugging != debugging)
	{
		member.debugging = debugging;
		if (member.paused_thread_id)
		{
			member.debugResume();
		}
		this->emit(Signal_Debugging, debugging);
	}
}
bool BScript::debugging() const
{
	AutoLock lock(this);
	return member.debugging;
}

bool BScript::insertBreakpoint(const BString& breakpoint)
{
	AutoLock lock(this);
	return member.breakpointSet.insert(breakpoint) >= 0;
}
bool BScript::removeBreakpoint(const BString& breakpoint)
{
	AutoLock lock(this);
	return member.breakpointSet.remove(breakpoint);
}
bool BScript::containBreakpoint(const BString& breakpoint)
{
	return member.breakpointSet.contain(breakpoint);
}
bool BScript::clearBreakpoints()
{
	AutoLock lock(this);
	member.breakpointSet.clear();
	return true;
}

int BScript::breakpointCount() const
{
	return member.breakpointSet.size();
}
const BString& BScript::breakpoint(int index) const
{
	return member.breakpointSet[index];
}

bool BScript::compile()
{
	AutoLock lock(this);

	if (member.running)
	{
		member.errorMessage() << "compile failed : script is running.";
		this->emit(Signal_Message, member.message);
		return false;
	}

	member.error = false;
	member.unlinked = false;
	member.message.clear();
	member.current = -1;
	member.global = 0;
	member.stack.clear();
	member.sequence.clear();
	member.inclibs.clear();
	member.declMap.clear();
	member.enumMap.clear();
	member.classMap.clear();
	member.functionMap.clear();

	if (member.sources.empty())
	{
		member.errorMessage() << "compile failed : script don't have sources.";
		this->emit(Signal_Message, member.message);
		return false;
	}

	AutoWorkPath workpath(member.path);
	if (workpath.failed())
	{
		member.errorMessage() << "Enter script path failed : " << member.path;
		this->emit(Signal_Message, member.message);
		return false;
	}

	for (int i = 0; i < member.sources.size(); i++)
	{
		BSource* source = member.sources[i];
		if (source->enabled())
		{
			if (this->checks(Signal_Analyse))
				this->emit(Signal_Analyse, source);
			if (!source->analyse())
				member.error = true;
		}
	}
	if (member.error)
		return false;

	member.combine();
	if (member.error)
		return false;

	member.serialize();
	if (member.error)
		return false;

	member.link();
	member.unlinked = false;
	if (member.error)
		return false;

	for (int i = 0; i < member.sources.size(); i++)
	{
		member.sources[i]->clean();
	}

	BString info;
	for (int i = 0; i < member.sequence.size(); i++)
	{
		BExp* exp = member.sequence[i];
		if (exp->info.empty())
			continue;
		int pos = exp->info.find('(');
		if (pos == exp->info.size())
			continue;
		exp->info.remove(pos, exp->info.size());
		if (exp->info == info)
			exp->info.clear();
		else
			info = exp->info;
	}
	member.current = -1;
	member.global = 0;
	member.stack.reset();
	member.stack.reserve(100);
	this->emit(Signal_Compiled, member.message);
	return true;
}
bool BScript::reset()
{
	AutoLock lock(this);
	if (!member.running)
	{
		member.error = false;
		member.running = false;
		member.current = -1;
		member.global = 0;
		member.stack.reset();
		member.stack.reserve(100);
		return true;
	}
	return false;
}
bool BScript::call(const BString& name, int argc, BValue* argv)
{
	if (this->running())
	{
		member.errorMessage() << "script is already running.";
		this->post(Signal_Error, member.message);
		return false;
	}
	this->lock();
	if (member.unlinked)
	{
		member.link();
		member.unlinked = false;
	}
	if (member.error)
	{
		member.errorMessage() << "script has error, not ready yet for running.";
		this->post(Signal_Error, member.message);
		return false;
	}
	if (member.sequence.empty())
	{
		this->unlock();
		return false;
	}
	member.running = true;
	member.command.clear();
	if (member.current < 0)
	{
		member.counter = 0;
		member.current = 0;
		member.global = 0;
		member.stack.reset();
		member.stack.reserve(100);
		member.nameMap.reset();
		member.typeMap.reserve(100);
		member.nameMap.reset();
		member.typeMap.reserve(100);
		this->unlock();
		this->lock();
		while (member.sequence.check(member.current))
		{
			BExp* exp = member.sequence[member.current];
			member.current = member.perform(exp);
			member.global = member.stack.size();
			object_member(this)->check_emit(Signal_Performed, ++member.counter);

			if (member.error)
			{
				member.running = false;
				this->unlock();
				return false;
			}
			this->unlock();
			this->lock();
			if (member.running == false)
			{
				this->unlock();
				return true;
			}
			if (member.debugging)
			{
				member.debug(exp);
				if (member.command == "stop")
				{
					member.command.clear();
					member.running = false;
					this->unlock();
					return true;
				}
			}
			member.routine();
		}
		this->emit(Signal_Inited, member.global);
	}
	this->unlock();
	this->lock();
	if (name.empty())
	{
		member.running = false;
		this->unlock();
		return true;
	}
	FuncInfo* finfo = member.findFunction(name);
	if (finfo == 0)
	{
		member.running = false;
		member.errorMessage() << "function " << name << " is unfound.";
		this->post(Signal_Error, member.message);
		this->unlock();
		return false;
	}
	if (finfo->params.size() != argc - 1)
	{
		member.running = false;
		member.errorMessage() << "function " << name << " params count don't match.";
		this->post(Signal_Error, member.message);
		this->unlock();
		return false;
	}
	if (finfo->sfunc)
	{
		int top = member.stack.size();
		member.typeMap[top] = finfo->type;
		BValue& res = member.stack.push();
		for (int i = 0; i < finfo->params.size(); i++)
		{
			ParamInfo& pinfo = finfo->params[i];
			member.typeMap[member.stack.size()] = pinfo.type;
			member.nameMap[member.stack.size()] = pinfo.name;
			member.stack.push(argv[i + 1]);
		}
		member.typeMap[member.stack.size()] = "call";
		member.nameMap[member.stack.size()] = finfo->sfunc->name;
		CallInfo* cinfo = new CallInfo();
		cinfo->type = finfo->type;
		cinfo->pos = member.sequence.size();
		cinfo->top = top;
		member.stack.push(cinfo);
		member.current = finfo->line;
		this->unlock();
		this->lock();
		while (member.current < member.sequence.size())
		{
			BExp* exp = member.sequence[member.current];
			member.current = member.perform(exp);
			object_member(this)->check_emit(Signal_Performed, ++member.counter);

			if (member.error)
			{
				member.running = false;
				this->unlock();
				return false;
			}
			this->unlock();
			this->lock();
			if (member.running == false)
			{
				this->unlock();
				return true;
			}
			if (member.debugging)
			{
				member.debug(exp);
				if (member.command == "stop")
				{
					member.command.clear();
					member.stack.back(top);
					member.running = false;
					this->unlock();
					return true;
				}
			}
			member.routine();
		}
		if (cinfo->type.size())
		{
			argv[0] = res;
		}
		member.stack.back(top);
		member.running = false;
		this->unlock();
		return true;
	}
	int size = member.stack.size();
	member.typeMap[size] = finfo->type;
	BValue& res = member.stack.push();
	for (int i = 0; i < finfo->params.size(); i++)
	{
		ParamInfo& pinfo = finfo->params[i];
		member.typeMap[member.stack.size()] = pinfo.type;
		member.nameMap[member.stack.size()] = pinfo.name;
		member.stack.push(argv[i]);
	}
	finfo->cfunc(argc, argv);
	if (finfo->type.size())
	{
		argv[0] = res;
	}
	member.stack.back(size);
	member.running = false;
	this->unlock();
	return true;
}
bool BScript::debug(const BString& command)
{
	if (this->lock())
	{
		if (member.paused_thread_id)
		{
			member.debugResume();
		}
		member.breaked = false;
		member.command = command;
		this->unlock();
		return true;
	}
	return false;
}
bool BScript::create(const BString& type, BValue& value, const BValue& param)
{
	BClass* cls = this->findClass(type);
	if (!cls)
	{
		BString message;
		message << "create [" << type << "] value failed : can't find class.";
		this->emit(Signal_Error, message);
		return false;
	}

	if (!class_member(cls)->ismeta)
	{
		if (BClass* self = cls->clone())
		{
			class_member(self)->script = this;
			value = self;
		}
	}

	BString methodName;
	if (param.empty())
	{
		methodName << type << '(' << ')';
		if (MethodInfo* minfo = class_member(cls)->methodMap(methodName))
		{
			if (BClass::Method method = minfo->method)
			{
				BClass* self = value;
				BValue argv[2] = { &value, &param };
				(self->*method)(2, argv);
				value = argv[0];
				return true;
			}
			BString message;
			message << "create [" << type << "] value failed.";
			this->emit(Signal_Error, message);
			return false;
		}
		return true;
	}

	methodName << type << "(const " << type << "&)";
	MethodInfo* minfo = class_member(cls)->methodMap(methodName);
	if (!minfo)
	{
		methodName.reset();
		methodName << type << '(' << type << ')';
		minfo = class_member(cls)->methodMap(methodName);
	}
	if (minfo)
	{
		if (BClass::Method method = minfo->method)
		{
			BClass* self = value;
			BValue argv[2] = { &value, &param };
			(self->*method)(2, argv);
			value = argv[0];
			return true;
		}
		BString message;
		message << "create [" << type << "] value failed.";
		this->emit(Signal_Error, message);
		return false;
	}
	value = param;
	return true;
}
bool BScript::error() const
{
	bool error = false;
	if (this->lock())
	{
		error = member.error;
		this->unlock();
	}
	return error;
}
bool BScript::inited() const
{
	bool inited = false;
	if (this->lock())
	{
		inited = member.current >= 0;
		this->unlock();
	}
	return inited;
}
bool BScript::breaked() const
{
	bool breaked = false;
	if (this->lock())
	{
		breaked = member.breaked;
		this->unlock();
	}
	return breaked;
}
bool BScript::running() const
{
	bool running = false;
	if (this->lock())
	{
		running = member.running;
		this->unlock();
	}
	return running;
}
bool BScript::stop() const
{
	if (this->lock())
	{
		if (member.running)
		{
			member.running = false;
			this->unlock();
			return true;
		}
		this->unlock();
	}
	return false;
}
bool BScript::clean()
{
	if (member.running)
	{
		BString message("clear script which is running.");
		this->emit(Signal_Error, message);
		return false;
	}
	member.current = -1;
	member.global = 0;
	member.stack.clear();
	member.sequence.clear();
	member.inclibs.clear();
	member.declMap.clear();
	member.enumMap.clear();
	member.classMap.clear();
	member.functionMap.clear();
	for (int i = 0; i < member.sources.size(); i++)
	{
		member.sources[i]->clean();
	}
	return true;
}

const BString& BScript::message() const
{
	return member.message;
}

int BScript::functionCount() const
{
	return member.functionMap.size();
}
const BExp* BScript::function(int index) const
{
	auto it = member.functionMap.seek(index);
	if (FuncInfo* finfo = it.value())
		return finfo->sfunc;
	return 0;
}
const BExp* BScript::function(int index, BString& name) const
{
	auto it = member.functionMap.seek(index);
	if (FuncInfo* finfo = it.value())
	{
		name = it.key();
		return finfo->sfunc;
	}
	return 0;
}
const BExp* BScript::function(int index, BString& type, BString& name) const
{
	auto it = member.functionMap.seek(index);
	if (FuncInfo* finfo = it.value())
	{
		type = finfo->type;
		name = it.key();
		return finfo->sfunc;
	}
	return 0;
}

BEnum* BScript::findEnum(const BString& type)
{
	if (type.endWith('&') || type.beginWith("const "))
	{
		BString temp = type;
		temp.remove("const ");
		temp -= '&';
		return findEnum(temp);
	}
	if (BEnum* enm = this->registedEnum(type))
		return enm;
	if (BEnum* enm = member.enumMap(type))
		return enm;
	return 0;
}
const BEnum* BScript::findEnum(const BString& type) const
{
	if (type.endWith('&') || type.beginWith("const "))
	{
		BString temp = type;
		temp.remove("const ");
		temp -= '&';
		return findEnum(temp);
	}
	if (const BEnum* enm = this->registedEnum(type))
		return enm;
	if (const BEnum* enm = member.enumMap(type))
		return enm;
	return 0;
}

BClass* BScript::findClass(const BString& type)
{
	if (type.endWith('&') || type.beginWith("const "))
	{
		BString temp = type;
		temp.remove("const ");
		temp -= '&';
		return findClass(temp);
	}
	if (BClass* cls = member.basicClassMap(type))
		return cls;
	if (BClass* cls = member.presetClassMap(type))
		return cls;
	if (BClass* cls = member.classMap(type))
		return cls;
	return 0;
}
const BClass* BScript::findClass(const BString& type) const
{
	if (type.endWith('&') || type.beginWith("const "))
	{
		BString temp = type;
		temp.remove("const ");
		temp -= '&';
		return findClass(temp);
	}
	if (const BClass* cls = member.basicClassMap(type))
		return cls;
	if (const BClass* cls = member.presetClassMap(type))
		return cls;
	if (const BClass* cls = member.classMap(type))
		return cls;
	return 0;
}

bool BScript::setValue(const BString& path, const BValue& value)
{
	if (member.global >= 0)
	{
		if (BValue* ptr = member.findVariant(path))
		{
			if (BClass* cls = *ptr)
				return false;
			*ptr = value;
			return true;
		}
	}
	return false;
}
const BValue& BScript::value(const BString& path)
{
	if (member.global >= 0)
	{
		if (BValue* ptr = member.findVariant(path))
		{
			return *ptr;
		}
	}
	return member.stack.def();
}

int BScript::stackCapacity() const
{
	return member.stack.capacity();
}
int BScript::stackSize() const
{
	return member.stack.size();
}
BValue& BScript::stack(int index)
{
	return member.stack(index);
}
BValue& BScript::stack(int index, BString& type, BString& name)
{
	type.reset();
	name.reset();
	BValue& value = member.stack(index);
	name << member.nameMap(index);
	if (value.is<BValue*>())
	{
		BString tstr, nstr;
		BValue* ptr = &value;
		while ((*ptr).is<BValue*>())
		{
			member.locateVariant(ptr, tstr, nstr);
			name << "->" << nstr;
			ptr = *ptr;
		}
		member.locateVariant(ptr, tstr, nstr);
		name << "->" << nstr;
		type = tstr;
	}
	else
	{
		type = member.typeMap(index);
	}
	return value;
}
const BValue& BScript::stack(int index) const
{
	return member.stack(index);
}
const BValue& BScript::stack(int index, BString& type, BString& name) const
{
	type = member.typeMap(index);
	name = member.nameMap(index);
	return member.stack(index);
}

bool BScript::setSequence(const BExpHolderArray& sequence)
{
	if (&member.sequence == &sequence)
		return true;
	member.sequence = sequence;
	BClass* cls = 0;
	for (int i = 0; i < sequence.size(); i++)
	{
		BExp* exp = sequence[i];
		if (exp->syntax == Syntax_Include)
		{
			exp->value = member.importLibrary(exp->name);
			member.inclibs.append(exp);
			continue;
		}
		if (exp->syntax == Syntax_Enum)
		{
			BEnum* enm = new BEnum(exp->name);
			for (int i = 0; i < exp->params.size(); i++)
			{
				BExp* param = exp->params[i];
				enm->append(param->name, param->value);
			}
			member.enumMap[exp->name] = enm;
			continue;
		}
		if (exp->syntax == Syntax_Class)
		{
			int begin = exp->name.find('<');
			if (begin < exp->name.size())
				cls = member.createTempClass(exp->name);
			else
				cls = new BClass(exp->name);
			for (int i = 0; i < exp->params.size(); i++)
			{
				BExp* param = exp->params[i];
				if (param->syntax == Syntax_Decl)
				{
					VariantInfo& var = class_member(cls)->variants.append();
					var.type = param->type;
					var.name = param->name;
					var.value = param->value;
					continue;
				}
				if (param->syntax == Syntax_Method)
				{
					MethodInfo* minfo = new MethodInfo(cls);
					minfo->virt = true;//only virtual method preset in class;
					minfo->method = param->value;
					class_member(cls)->methodMap[param->name] = minfo;
					continue;
				}
				class_member(cls)->inherits.append(param);
			}
			exp->value = cls;
			member.classMap[exp->name] = cls;
			continue;
		}
		if (exp->syntax == Syntax_Method)
		{
			if (!cls)
			{
				member.errorMessage(exp) << "regist method " << exp->name << "failed, out of class.";
				this->emit(Signal_Message, member.message);
				continue;
			}
			MethodInfo* minfo = class_member(cls)->methodMap[exp->name];
			if (!minfo)//this is not virtual method.
			{
				minfo = new MethodInfo(cls);
				class_member(cls)->methodMap[exp->name] = minfo;
			}
			minfo->type = exp->type;
			minfo->method = exp;
			minfo->line = i;
			for (int i = 0; i < exp->params.size(); i++)
			{
				BExp* param = exp->params[i];
				ParamInfo& var = minfo->params.append();
				var.type = param->type;
				var.name = param->name;
				var.value = param->value;
			}
			continue;
		}
		if (exp->syntax == Syntax_Function)
		{
			cls = 0;
			FuncInfo* finfo = new FuncInfo();
			finfo->type = exp->type;
			finfo->sfunc = exp;
			finfo->line = i;
			for (int i = 0; i < exp->params.size(); i++)
			{
				BExp* param = exp->params[i];
				ParamInfo& var = finfo->params.append();
				var.type = param->type;
				var.name = param->name;
				var.value = param->value;
			}
			member.functionMap[exp->name] = finfo;
			continue;
		}
	}
	if (member.error)
		return false;
	member.unlinked = true;
	return true;
}
const BExpHolderArray& BScript::sequence() const
{
	return member.sequence;
}

bool BScript::query(const BString& text, BValue& value) const
{
	if (text == "counter")
	{
		value = member.counter;
		return true;
	}
	if (text == "basic-classes")
	{
		BMap<BString, BClass*>& classMap = value.fill<BMap<BString, BClass*>>();
		classMap = member.basicClassMap;
		return true;
	}
	if (text == "sequence")
	{
		BExpHolderArray& sequence = value.fill<BExpHolderArray>();
		sequence = member.sequence;
		return true;
	}
	if (text == "classes")
	{
		BMap<BString, BClass*>& classMap = value.fill<BMap<BString, BClass*>>();
		classMap = member.classMap;
		return true;
	}
	if (text == "functions")
	{
		BStringArray& funcNames = value.fill<BStringArray>();
		funcNames.reset();
		BString text;
		for (auto it = member.functionMap.begin(); it.valid(); ++it)
		{
			text.reset();
			if (it.value()->type.empty())
				text.append("void");
			else
				text.append(it.value()->type);
			text.append(' ');
			text.append(it.key());
			funcNames.append(text);
		}
		return true;
	}
	if (text == "registed-classes")
	{
		BMap<BString, BClass*>& classMap = value.fill<BMap<BString, BClass*>>();
		classMap = member.presetClassMap;
		return true;
	}
	if (text == "registed-functions")
	{
		BMap<BString, Function>& cfuncMap = value.fill<BMap<BString, Function>>();
		for (auto it = member.presetFunctionMap.begin(); it.valid(); ++it)
		{
			FuncInfo* finfo = *it;
			cfuncMap.insert(it.key(), finfo->cfunc);
		}
		return true;
	}
	if (text == "registed-variants")
	{
		BArray<VariantInfo>& variants = value.fill<BArray<VariantInfo>>();
		variants = member.presetVariants;
		return true;
	}
	return BObject::query(text, value);
}
